package com.alibaba.smart.framework.engine.test.process;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.smart.framework.engine.configuration.ConfigurationOption;
import com.alibaba.smart.framework.engine.model.assembly.ProcessDefinition;
import com.alibaba.smart.framework.engine.model.instance.ActivityInstance;
import com.alibaba.smart.framework.engine.model.instance.InstanceStatus;
import com.alibaba.smart.framework.engine.model.instance.ProcessInstance;
import com.alibaba.smart.framework.engine.model.instance.TaskAssigneeInstance;
import com.alibaba.smart.framework.engine.model.instance.TaskInstance;
import com.alibaba.smart.framework.engine.test.DatabaseBaseTestCase;
import com.alibaba.smart.framework.engine.test.process.helper.CustomExceptioinProcessor;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import static org.junit.Assert.assertEquals;

@ContextConfiguration("/spring/application-test.xml")
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
public class DataBaseAuditProcessExample extends DatabaseBaseTestCase {


  @Override
  protected void initProcessConfiguration() {
    super.initProcessConfiguration();
    processEngineConfiguration.setExceptionProcessor(new CustomExceptioinProcessor());
    processEngineConfiguration.getOptionContainer().put(ConfigurationOption.TRANSFER_ENABLED_OPTION);
  }

  @Test
  public void testAuditProcess() throws Exception {


    ProcessDefinition processDefinition = repositoryCommandService
        .deploy("test-usertask-and-servicetask-exclusive.bpmn20.xml").getFirstProcessDefinition();
    assertEquals(17, processDefinition.getBaseElementList().size());

    //4.启动流程实例
    ProcessInstance processInstance = processCommandService.start(
        processDefinition.getId(), processDefinition.getVersion()
    );
    Assert.assertNotNull(processInstance);

    List<TaskInstance> submitTaskInstanceList = taskQueryService.findAllPendingTaskList(processInstance.getInstanceId());
    TaskInstance submitTaskInstance = submitTaskInstanceList.get(0);

    //5.流程流转:构造提交申请参数
    Map<String, Object> submitFormRequest = new HashMap<String, Object>();
    submitFormRequest.put("title", "new_title");
    submitFormRequest.put("qps", "300");
    submitFormRequest.put("capacity", "10g");
    submitFormRequest.put("assigneeUserId", "1");

    //6.流程流转:处理 submitTask,完成任务申请.
    taskCommandService.complete(submitTaskInstance.getInstanceId(), submitFormRequest);

    //7. 获取当前待处理任务.
    List<TaskInstance> auditTaskInstanceList = taskQueryService.findAllPendingTaskList(processInstance.getInstanceId());
    TaskInstance auditTaskInstance = auditTaskInstanceList.get(0);
    Map<String, Object> approveFormRequest = new HashMap<String, Object>();

    //10.
    approveFormRequest.put("approve", "agree");
    approveFormRequest.put("desc", "ok");

    //9.审批通过,驱动流程节点到自动执行任务环节


    //9.5 test transfer api,just ignore
    assertTransferAPI(auditTaskInstance);

    taskCommandService.complete(auditTaskInstance.getInstanceId(), approveFormRequest);

    //10.由于流程测试已经关闭,需要断言没有需要处理的人,状态关闭.
    ProcessInstance finalProcessInstance = processQueryService.findById(auditTaskInstance.getProcessInstanceId());
    assertEquals(InstanceStatus.completed, finalProcessInstance.getStatus());


    List<ActivityInstance> activityInstanceList = activityQueryService.findAll(processInstance.getInstanceId());
    Assert.assertEquals(6, activityInstanceList.size());

    ActivityInstance activityInstance = activityInstanceList.get(0);

    Assert.assertNotNull(activityInstance.getStartTime());

  }

  private void assertTransferAPI(TaskInstance auditTaskInstance) {
    taskCommandService.transfer(auditTaskInstance.getInstanceId(), "3", "4");
    List<TaskAssigneeInstance> list = taskAssigneeQueryService.findList(auditTaskInstance.getInstanceId());
    Assert.assertEquals(3, list.size());

    List<String> arrayList = new ArrayList<String>();

    for (TaskAssigneeInstance taskAssigneeInstance : list) {
      arrayList.add(taskAssigneeInstance.getAssigneeId());
    }

    Assert.assertTrue(arrayList.contains("1"));
    Assert.assertTrue(arrayList.contains("4"));
    Assert.assertTrue(arrayList.contains("5"));
  }

  @Test
  public void testFailedServiceTaskAuditProcess() throws Exception {


    ProcessDefinition processDefinition = repositoryCommandService
        .deploy("failed-test-usertask-and-servicetask-exclusive.bpmn20.xml").getFirstProcessDefinition();
    assertEquals(17, processDefinition.getBaseElementList().size());

    //4.启动流程实例
    ProcessInstance processInstance = processCommandService.start(
        processDefinition.getId(), processDefinition.getVersion()
    );
    Assert.assertNotNull(processInstance);

    List<TaskInstance> submitTaskInstanceList = taskQueryService.findAllPendingTaskList(processInstance.getInstanceId());
    TaskInstance submitTaskInstance = submitTaskInstanceList.get(0);

    //5.流程流转:构造提交申请参数
    Map<String, Object> submitFormRequest = new HashMap<String, Object>();
    submitFormRequest.put("qps", "300");
    submitFormRequest.put("capacity", "10g");
    submitFormRequest.put("assigner", "leader");

    //6.流程流转:处理 submitTask,完成任务申请.
    taskCommandService.complete(submitTaskInstance.getInstanceId(), submitFormRequest);

    //7. 获取当前待处理任务.
    List<TaskInstance> auditTaskInstanceList = taskQueryService.findAllPendingTaskList(processInstance.getInstanceId());
    TaskInstance auditTaskInstance = auditTaskInstanceList.get(0);
    Map<String, Object> approveFormRequest = new HashMap<String, Object>();

    //10.
    approveFormRequest.put("approve", "agree");
    approveFormRequest.put("desc", "ok");

    //9.审批通过,驱动流程节点到自动执行任务环节

    taskCommandService.complete(auditTaskInstance.getInstanceId(), approveFormRequest);

    //10.由于流程测试已经关闭,需要断言没有需要处理的人,状态关闭.
    ProcessInstance finalProcessInstance = processQueryService.findById(auditTaskInstance.getProcessInstanceId());
    assertEquals(InstanceStatus.completed, finalProcessInstance.getStatus());


  }


}